// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/web_contents/aura/overscroll_window_delegate.h"

#include "base/i18n/rtl.h"
#include "content/browser/frame_host/navigation_controller_impl.h"
#include "content/browser/frame_host/navigation_entry_impl.h"
#include "content/browser/renderer_host/overscroll_controller_delegate.h"
#include "content/public/browser/overscroll_configuration.h"
#include "ui/aura/window.h"
#include "ui/events/event.h"
#include "ui/gfx/image/image_png_rep.h"

namespace content {

OverscrollWindowDelegate::OverscrollWindowDelegate(
    OverscrollControllerDelegate* delegate,
    const gfx::Image& image)
    : delegate_(delegate)
    , overscroll_mode_(OVERSCROLL_NONE)
    , delta_x_(0.f)
    , complete_threshold_ratio_(content::GetOverscrollConfig(
          content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE))
    , start_threshold_touchscreen_(content::GetOverscrollConfig(
          content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN))
    , start_threshold_touchpad_(content::GetOverscrollConfig(
          content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHPAD))
    , active_start_threshold_(0.f)
{
    SetImage(image);
}

OverscrollWindowDelegate::~OverscrollWindowDelegate()
{
}

void OverscrollWindowDelegate::StartOverscroll()
{
    OverscrollMode old_mode = overscroll_mode_;
    if (delta_x_ > 0)
        overscroll_mode_ = OVERSCROLL_EAST;
    else
        overscroll_mode_ = OVERSCROLL_WEST;
    delegate_->OnOverscrollModeChange(old_mode, overscroll_mode_);
}

void OverscrollWindowDelegate::ResetOverscroll()
{
    if (overscroll_mode_ == OVERSCROLL_NONE)
        return;
    delegate_->OnOverscrollModeChange(overscroll_mode_, OVERSCROLL_NONE);
    overscroll_mode_ = OVERSCROLL_NONE;
    delta_x_ = 0;
}

void OverscrollWindowDelegate::CompleteOrResetOverscroll()
{
    if (overscroll_mode_ == OVERSCROLL_NONE)
        return;
    int width = delegate_->GetVisibleBounds().width();
    float ratio = (fabs(delta_x_)) / width;
    if (ratio < complete_threshold_ratio_) {
        ResetOverscroll();
        return;
    }
    delegate_->OnOverscrollComplete(overscroll_mode_);
    overscroll_mode_ = OVERSCROLL_NONE;
    delta_x_ = 0;
}

void OverscrollWindowDelegate::UpdateOverscroll(float delta_x)
{
    float old_delta_x = delta_x_;
    delta_x_ += delta_x;
    if (overscroll_mode_ == OVERSCROLL_NONE) {
        if (fabs(delta_x_) > active_start_threshold_)
            StartOverscroll();
        return;
    }
    if ((old_delta_x < 0 && delta_x_ > 0) || (old_delta_x > 0 && delta_x_ < 0)) {
        ResetOverscroll();
        return;
    }
    delegate_->OnOverscrollUpdate(delta_x_, 0.f);
}

void OverscrollWindowDelegate::OnKeyEvent(ui::KeyEvent* event)
{
    ResetOverscroll();
}

void OverscrollWindowDelegate::OnMouseEvent(ui::MouseEvent* event)
{
    if (!(event->flags() & ui::EF_IS_SYNTHESIZED) && event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) {
        ResetOverscroll();
    }
}

void OverscrollWindowDelegate::OnScrollEvent(ui::ScrollEvent* event)
{
    active_start_threshold_ = start_threshold_touchpad_;
    if (event->type() == ui::ET_SCROLL)
        UpdateOverscroll(event->x_offset_ordinal());
    else if (event->type() == ui::ET_SCROLL_FLING_START)
        CompleteOrResetOverscroll();
    else
        ResetOverscroll();
    event->SetHandled();
}

void OverscrollWindowDelegate::OnGestureEvent(ui::GestureEvent* event)
{
    active_start_threshold_ = start_threshold_touchscreen_;
    switch (event->type()) {
    case ui::ET_GESTURE_SCROLL_UPDATE:
        UpdateOverscroll(event->details().scroll_x());
        break;

    case ui::ET_GESTURE_SCROLL_END:
        CompleteOrResetOverscroll();
        break;

    case ui::ET_SCROLL_FLING_START:
        CompleteOrResetOverscroll();
        break;

    case ui::ET_GESTURE_PINCH_BEGIN:
    case ui::ET_GESTURE_PINCH_UPDATE:
    case ui::ET_GESTURE_PINCH_END:
        ResetOverscroll();
        break;

    default:
        break;
    }
    event->SetHandled();
}

} // namespace content
